package cn.lingyangwl.agile.tenant.core;

import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.constants.RequestCons.*;
import cn.lingyangwl.agile.model.module.tenant.*;
import cn.lingyangwl.agile.tenant.core.utils.*;
import cn.lingyangwl.framework.tool.core.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.Optional;

/**
 * 操作日志记录处理
 *
 * @author shenguangyang
 */
@Slf4j
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
public class TenantAspect {

    @Around("@annotation(tenantAnn)")
    public Object around(ProceedingJoinPoint point, Tenant tenantAnn) throws Throwable {
        DataIsolateLevel isolateLevel = tenantAnn.level();
        if (!TenantContext.get().isMgtSceneTenant() && tenantAnn.mustEqMgtScene()) {
            throw new BizException("当前操作只允许在管理端进行");
        }

        try {
            String tenantId = TenantContext.get().getTenantId();
            if (StringUtils.isEmpty(tenantId) || TenantContext.EMPTY_TENANT_ID.equals(tenantId)) {
                return point.proceed();
            }

            return TenantUtils.execute(isolateLevel, () -> {
                try {
                    return point.proceed();
                } catch (BaseException e) {
                    log.warn("tenantInfo: {}", JSON.toJSONString(TenantContext.get()));
                    throw e;
                } catch (Throwable e) {
                    log.error("error: ", e);
                    throw new RuntimeException(e);
                }
            });
        } finally {
            // 如果是查询管理场景查询, 设置租户id到响应头中
            if (DataIsolateLevel.MGT == isolateLevel) {
                HttpServletResponse response = Optional.ofNullable( RequestContextHolder.getRequestAttributes())
                    .map(e -> ((ServletRequestAttributes) e).getResponse()).orElse(null);
                if (Objects.nonNull(response)) {
                    response.setHeader(Headers.TENANT_ID, TenantContext.get().getMgtSceneTenantId() + "");
                }
            }
        }
    }
}
